import { DataObject } from '@/utils/types';

export const isMobile = (s: string): boolean => {
  return /^1[0-9]{10}$/.test(s);
};

export const isPhone = (s: string): boolean => {
  return /^([0-9]{3,4}-)?[0-9]{7,8}$/.test(s);
};

export const isURL = (s: string): boolean => {
  return /^http[s]?:\/\/.*/.test(s);
};

export const check = (s: string, type: string): boolean => {
  switch (type) {
    case 'Phone': //手机号码
      return /^1[3|4|5|6|7|8|9][0-9]{9}$/.test(s);
    case 'Tel': //座机
      return /^(0\d{2,3}-\d{7,8})(-\d{1,4})?$/.test(s);
    case 'Card': //身份证
      return /(^\d{15}$)|(^\d{18}$)|(^\d{17}(\d|X|x)$)/.test(s);
    case 'Password': //密码以字母开头，长度在6~18之间，只能包含字母、数字和下划线
      return /^[a-zA-Z]\w{5,17}$/.test(s);
    case 'Postal': //邮政编码
      return /[1-9]\d{5}(?!\d)/.test(s);
    case 'QQ': //QQ号
      return /^[1-9][0-9]{4,9}$/.test(s);
    case 'Email': //邮箱
      return /^\w+((.\w+)|(-\w+))@[A-Za-z0-9]+((.|-)[A-Za-z0-9]+).[A-Za-z0-9]+$/.test(s);
    case 'Money': //金额(小数点2位)
      return /^\d*(?:\.\d{0,2})?$/.test(s);
    case 'URL': //网址
      return /(http|ftp|https):\/\/[\w\-_]+(\.[\w\-_]+)+([\w\-.,@?^=%&:/~+#]*[\w\-@?^=%&/~+#])?/.test(s);
    case 'IP': //IP
      return /((?:(?:25[0-5]|2[0-4]\\d|[01]?\\d?\\d)\\.){3}(?:25[0-5]|2[0-4]\\d|[01]?\\d?\\d))/.test(s);
    case 'Date': //日期时间
      return (
        /^(\d{4})-(\d{2})-(\d{2}) (\d{2})(?::\d{2}|:(\d{2}):(\d{2}))$/.test(s) || /^(\d{4})-(\d{2})-(\d{2})$/.test(s)
      );
    case 'Number': //数字
      return /^[0-9]$/.test(s);
    case 'English': //英文
      return /^[a-zA-Z]+$/.test(s);
    case 'Chinese': //中文
      return /^[\\u4E00-\\u9FA5]+$/.test(s);
    case 'Lower': //小写
      return /^[a-z]+$/.test(s);
    case 'Upper': //大写
      return /^[A-Z]+$/.test(s);
    case 'HTML': //HTML标记
      return /<("[^"]*"|'[^']*'|[^'">])*>/.test(s);
    default:
      return true;
  }
};

export const isCardID = (id: string): boolean => {
  if (!/(^\d{15}$)|(^\d{17}(\d|X|x)$)/.test(id)) {
    console.log('你输入的身份证长度或格式错误');
    return false;
  }
  //身份证城市
  const cities: { [key: number]: string } = {
    11: '北京',
    12: '天津',
    13: '河北',
    14: '山西',
    15: '内蒙古',
    21: '辽宁',
    22: '吉林',
    23: '黑龙江',
    31: '上海',
    32: '江苏',
    33: '浙江',
    34: '安徽',
    35: '福建',
    36: '江西',
    37: '山东',
    41: '河南',
    42: '湖北',
    43: '湖南',
    44: '广东',
    45: '广西',
    46: '海南',
    50: '重庆',
    51: '四川',
    52: '贵州',
    53: '云南',
    54: '西藏',
    61: '陕西',
    62: '甘肃',
    63: '青海',
    64: '宁夏',
    65: '新疆',
    71: '台湾',
    81: '香港',
    82: '澳门',
    91: '国外',
  };
  if (!cities[parseInt(id.substr(0, 2))]) {
    console.log('你的身份证地区非法');
    return false;
  }
  // 出生日期验证
  const birthday = `${id.substr(6, 4)}/${Number(id.substr(10, 2))}/${Number(id.substr(12, 2))}`;
  const date = new Date(birthday);
  if (birthday !== `${date.getFullYear()}/${date.getMonth() + 1}/${date.getDate()}`) {
    console.log('身份证上的出生日期非法');
    return false;
  }
  // 身份证号码校验
  const weights = [7, 9, 10, 5, 8, 4, 2, 1, 6, 3, 7, 9, 10, 5, 8, 4, 2];
  const codes = '10X98765432';
  let sum = 0;
  for (let i = 0; i < id.length - 1; i++) {
    sum += Number(id[i]) * weights[i];
  }
  const last = codes[sum % 11]; //计算出来的最后一位身份证号码
  if (id[id.length - 1] !== String(last)) {
    console.log('你输入的身份证号非法');
    return false;
  }
  return true;
};

export const isString = (o: unknown): o is string => {
  return Object.prototype.toString.call(o).slice(8, -1) === 'String';
};

export const isNumber = (o: unknown): o is number => {
  return Object.prototype.toString.call(o).slice(8, -1) === 'Number';
};

export const isBoolean = (o: unknown): o is boolean => {
  return Object.prototype.toString.call(o).slice(8, -1) === 'Boolean';
};

export const isFunction = (o: unknown): boolean => {
  return Object.prototype.toString.call(o).slice(8, -1) === 'Function';
};

export const isNull = (o: unknown): o is null => {
  return Object.prototype.toString.call(o).slice(8, -1) === 'Null';
};

export const isUndefined = (o: unknown): o is undefined => {
  return Object.prototype.toString.call(o).slice(8, -1) === 'Undefined';
};

export const isObject = (o: unknown): o is DataObject => {
  return Object.prototype.toString.call(o).slice(8, -1) === 'Object';
};

export const isArray = <T>(o: unknown): o is Array<T> => {
  return Object.prototype.toString.call(o).slice(8, -1) === 'Array';
};

export const isDate = (o: unknown): o is Date => {
  return Object.prototype.toString.call(o).slice(8, -1) === 'Date';
};

export const isRegExp = (o: unknown): o is RegExp => {
  return Object.prototype.toString.call(o).slice(8, -1) === 'RegExp';
};

export const isError = (o: unknown): o is Error => {
  return Object.prototype.toString.call(o).slice(8, -1) === 'Error';
};

export const isSymbol = (o: unknown): o is symbol => {
  return Object.prototype.toString.call(o).slice(8, -1) === 'Symbol';
};

export const isPromise = <T>(o: unknown): o is Promise<T> => {
  return Object.prototype.toString.call(o).slice(8, -1) === 'Promise';
};

export const isSet = <T>(o: unknown): o is Set<T> => {
  return Object.prototype.toString.call(o).slice(8, -1) === 'Set';
};

export const userAgent = (): string => navigator.userAgent;

export const isWeiXin = (): boolean => {
  return (
    (userAgent()
      .toLowerCase()
      .match(/microMessenger/i) as unknown) === 'micromessenger'
  );
};

export const isDeviceMobile = (): boolean => {
  return /android|webos|iphone|ipod|balckberry/i.test(userAgent().toLowerCase());
};

export const isQQBrowser = (): boolean => {
  return !!userAgent()
    .toLowerCase()
    .match(/mqqbrowser|qzone|qqbrowser|qbwebviewtype/i);
};

export const isSpider = (): boolean => {
  return /adsbot|googlebot|bingbot|msnbot|yandexbot|baidubot|robot|careerbot|seznambot|bot|baiduspider|jikespider|symantecspider|scannerlwebcrawler|crawler|360spider|sosospider|sogou web sprider|sogou orion spider/.test(
    userAgent().toLowerCase()
  );
};

export const isIos = (): boolean => {
  const ua = userAgent();
  if (ua.indexOf('Android') > -1 || ua.indexOf('Linux') > -1) {
    //安卓手机
    return false;
  } else if (ua.indexOf('iPhone') > -1) {
    //苹果手机
    return true;
  } else if (ua.indexOf('iPad') > -1) {
    //iPad
    return false;
  } else if (ua.indexOf('Windows Phone') > -1) {
    //winphone手机
    return false;
  } else {
    return false;
  }
};

export const isPC = (): boolean => {
  const ua = userAgent();
  const Agents = ['Android', 'iPhone', 'SymbianOS', 'Windows Phone', 'iPad', 'iPod'];
  let flag = true;
  for (let v = 0; v < Agents.length; v++) {
    if (ua.indexOf(Agents[v]) > 0) {
      flag = false;
      break;
    }
  }
  return flag;
};

export const removeHtmltag = (s: string): string => {
  return s.replace(/<[^>]+>/g, '');
};

// export const injectScript = (src: string): void => {
// 	const s = document.createElement('script');
// 	s.type = 'text/javascript';
// 	s.async = true;
// 	s.src = src;
// 	const t = document.getElementsByTagName('script')[0];
// 	t.parentNode?.insertBefore(s, t);
// };

export const download = (url: string): boolean => {
  const isChrome = navigator.userAgent.toLowerCase().indexOf('chrome') > -1;
  const isSafari = navigator.userAgent.toLowerCase().indexOf('safari') > -1;
  if (isChrome || isSafari) {
    const link = document.createElement('a');
    link.href = url;
    if (link.download !== undefined) {
      link.download = url.substring(url.lastIndexOf('/') + 1, url.length);
    }
    if (document.createEvent) {
      const e = document.createEvent('MouseEvents');
      e.initEvent('click', true, true);
      link.dispatchEvent(e);
      return true;
    }
  }
  if (url.indexOf('?') === -1) {
    url += '?download';
  }
  window.open(url, '_self');
  return true;
};

export const hasClass = (el: Element, className: string): boolean => {
  const reg = new RegExp('(^|\\s)' + className + '(\\s|$)');
  return reg.test(el.className);
};

export const addClass = (el: Element, className: string): void => {
  if (!hasClass(el, className)) {
    const newClasses = el.className.split(' ');
    newClasses.push(className);
    el.className = newClasses.join(' ');
  }
};

export const removeClass = (el: Element, className: string): void => {
  if (hasClass(el, className)) {
    const reg = new RegExp('(^|\\s)' + className + '(\\s|$)', 'g');
    el.className = el.className.replace(reg, ' ');
  }
};

export const getPageScroll = (): {
  x: number;
  y: number;
} => ({
  x: window.pageXOffset,
  y: window.pageYOffset,
});

export const getElementScroll = (
  el: Element
): {
  x: number;
  y: number;
} => ({
  x: el.scrollLeft,
  y: el.scrollTop,
});

export const scrollToTop = (): void => {
  const c = document.documentElement.scrollTop || document.body.scrollTop;
  if (c > 0) {
    window.requestAnimationFrame(scrollToTop);
    window.scrollTo(0, c - c / 8);
  }
};

export const elementIsVisibleInViewport = (el: Element, partiallyVisible = false): boolean => {
  const { top, left, bottom, right } = el.getBoundingClientRect();
  const { innerHeight, innerWidth } = window;
  return partiallyVisible
    ? ((top > 0 && top < innerHeight) || (bottom > 0 && bottom < innerHeight)) &&
        ((left > 0 && left < innerWidth) || (right > 0 && right < innerWidth))
    : top >= 0 && left >= 0 && bottom <= innerHeight && right <= innerWidth;
};

export const copyTextToClipboard = (s: string): void => {
  const textArea = document.createElement('textarea');
  textArea.style.background = 'transparent';
  textArea.value = s;
  document.body.appendChild(textArea);
  textArea.select();
  try {
    document.execCommand('copy');
  } catch (err) {
    console.log('Oops, unable to copy');
  }
  document.body.removeChild(textArea);
};

export const addScript = (src: string): void => {
  const new_element = document.createElement('script');
  new_element.setAttribute('type', 'text/javascript');
  new_element.setAttribute('src', src);
  document.body.appendChild(new_element);
};

export const randomString = (length: number): string => {
  const template = 'ABCDEFGHJKMNPQRSTWXYZabcdefhijkmnprstwxyz2345678';
  let ret = '';
  for (let i = 0; i < length; i++) {
    ret += template.charAt(Math.floor(Math.random() * template.length));
  }
  return ret;
};

export const sleep = (time: number): Promise<void> => {
  return new Promise(resolve => setTimeout(resolve, time));
};

export const notEmpty = (arr: unknown[]): boolean => {
  return arr && arr.length > 0;
};

export const isEmpty = (arr: unknown[]): boolean => {
  return !notEmpty(arr);
};
